package com.tansun.easycare.rule.table.exclusions.service.impl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.tansun.easycare.rule.common.rulebasebean.Action;
import com.tansun.easycare.rule.common.rulebasebean.DThen;
import com.tansun.easycare.rule.common.rulebasebean.DWhen;
import com.tansun.easycare.rule.common.rulebasebean.Fact;
import com.tansun.easycare.rule.common.rulebasebean.RuleCollection;
import com.tansun.easycare.rule.common.rulebasebean.RuleItem;
import com.tansun.easycare.rule.common.service.impl.RuleBaseServiceImpl;
import com.tansun.easycare.rule.exception.BizException;
import com.tansun.easycare.rule.referencedata.entity.RuleReferenceData;
import com.tansun.easycare.rule.referencedata.service.RuleReferenceDataService;
import com.tansun.easycare.rule.rulemange.entity.RuleManage;
import com.tansun.easycare.rule.rulemange.service.RuleManageService;
import com.tansun.easycare.rule.ruleversion.entity.RuleVersioninfo;
import com.tansun.easycare.rule.ruleversion.service.RuleVersioninfoService;
import com.tansun.easycare.rule.table.dao.RuleDecisiontableDetailDao;
import com.tansun.easycare.rule.table.entity.RuleDecisiontableDetail;
import com.tansun.easycare.rule.table.exclusions.entity.ExclusionsBO;
import com.tansun.easycare.rule.table.exclusions.entity.ExclusionsVo;
import com.tansun.easycare.rule.table.exclusions.service.ExclusionsService;
import com.tansun.easycare.rule.utils.DroolsUtils;
import com.tansun.rule.common.RuleModelTypeEnum;
import com.tansun.rule.utils.StringUtils;

/**
 * 20160825
 *
 * @author linmin
 */
@Service("ExclusionsService")
public class ExclusionsServiceImpl extends RuleBaseServiceImpl<RuleDecisiontableDetailDao, RuleDecisiontableDetail> implements ExclusionsService {

    @Autowired
    private RuleManageService ruleManageService;
    @Autowired
    private RuleVersioninfoService ruleVersioninfoService;
    @Autowired
    private RuleReferenceDataService ruleReferenceDataService;

    /**
     * 保存或更新
     */
    public void saveOrUpdate(ExclusionsVo exclusionsVo) throws Exception {
        RuleManage ruleManage = exclusionsVo.getExclusionsModel();
        ruleManage.setStatus("1");
        ruleManage.setModelType(RuleModelTypeEnum.Exclusions.getCode());
        ruleManage = ruleManageService.saveOrUpdate(ruleManage);

        String context = saveExclusionsDrl(ruleManage, exclusionsVo.getExclusionsList());
        if (context == null)
            throw new BizException("未产生drl内容");
        RuleVersioninfo ruleVersioninfo = new RuleVersioninfo();
        ruleVersioninfo.init(ruleManage, context);
        this.ruleVersioninfoService.save(ruleVersioninfo);
        List<RuleDecisiontableDetail> newList = new ArrayList<RuleDecisiontableDetail>();
        Map<String, RuleReferenceData> dataMap = new HashMap();
        for (ExclusionsBO exclusionsBO : exclusionsVo.getExclusionsList()) {
            exclusionsBO.setManageId(ruleManage.getId());
            newList.add(exclusionsBO);
            this.ruleReferenceDataService.collectTableDetail(exclusionsBO, dataMap, ruleManage);
            for (ExclusionsBO outBO : exclusionsBO.getList()) {
                newList.add(outBO);
                this.ruleReferenceDataService.collectTableDetail(outBO, dataMap, ruleManage);
            }
        }
        this.insertBatch(newList, new String[]{"manageId", "projectCode", "version", "modelType"},
                new Object[]{ruleManage.getId(), ruleManage.getProjectCode(), ruleManage.getVersion(), ruleManage.getModelType()});
        this.ruleReferenceDataService.saveReferenceData(dataMap);
    }

    /**
     * 根据ID和版本号查找排除项明细信息
     */
    public List<ExclusionsBO> findExclusionItemByIndexId(String indexId, String version) throws BizException {

        RuleDecisiontableDetail decisiontableDetail = new RuleDecisiontableDetail();
        decisiontableDetail.setManageId(indexId);
        decisiontableDetail.setVersion(version);
        List<RuleDecisiontableDetail> list = this.dao.findList(decisiontableDetail);
        if (list == null) return null;
        List<ExclusionsBO> result = new ArrayList<ExclusionsBO>();
        ExclusionsBO inItem = null;
        try {

            for (RuleDecisiontableDetail tableDetail : list) { //排序列表
                if (tableDetail.getColumnNo() == 0) {
                    inItem = new ExclusionsBO();
                    BeanUtils.copyProperties(inItem, tableDetail);
                    result.add(inItem);
                } else {
                    ExclusionsBO outItem = new ExclusionsBO();
                    BeanUtils.copyProperties(outItem, tableDetail);
                    inItem.getList().add(outItem);
                }

            }
        } catch (Exception e) {
            throw new BizException(e, "E-000000");
        }
        return result;
    }

    /**
     * 保存 Drl 文件
     */
    private String saveExclusionsDrl(RuleManage exclusionsModel, List<ExclusionsBO> exclusionsList) throws Exception {
        if (CollectionUtils.isEmpty(exclusionsList)) {
            return null;
        }
        RuleCollection ruleCollection = new RuleCollection();
        ruleCollection.setDrlName(exclusionsModel.getCode());
        ruleCollection.setObjName(exclusionsModel.getName());
        ruleCollection.setContentType(RuleCollection.EXCLUSIONS);
        ruleCollection.setVersion(exclusionsModel.getVersion());

        // 生成动作组，优先级从 1 开始递减
        int salience = 1;
        for (ExclusionsBO exclusionsitem : exclusionsList) {
            String rdId = StringUtils.GenerateRandom(6);
            String ruleName = "exclusions_" + rdId;
            String whenExp = generateDrools(exclusionsitem, "when");

            String thenExp = "";
            for (ExclusionsBO listItem : exclusionsitem.getList()) {
                thenExp += generateDrools(listItem, "then");
            }

            RuleItem ruleItem = generateRuleItem(ruleName, salience, whenExp, thenExp);
            ruleCollection.getListItem().add(ruleItem);

            salience--;
        }

        // 写入DRL文件
//		ruleCollection.setSavePath(exclusionsModel.getItemPath().replace(".xml", ".drl"));
        return DroolsUtils.convert2Drl(ruleCollection);
    }

    /**
     * 生成 Drools 表达式
     */
    private String generateDrools(ExclusionsBO item, String type) {
        String retStr = "";
        String controlValue = item.getControlValue();
        String dataType = item.getDataType();

        if ("when".equals(type)) {
            retStr = "this[\"" + item.getClassName() + "\"][\"" + item.getNameen() + "\"]";
            if (!StringUtils.isEmpty(item.getPosition())) {
                retStr += ".get(" + item.getPosition() + ")";
            }

            if ("String".equals(item.getDataType())) {
                if (!StringUtils.isEmpty(item.getDomain()) && item.getControlValue().indexOf("[") >= 0) {
                    controlValue = item.getControlValue().substring(1, item.getControlValue().length() - 1);

                    // 排除项取值区间
                    retStr += " in (" + controlValue + ") ";
                } else {
                    // 排除项取值区间

                    retStr += "== " + "\"" + item.getControlValue() + "\"";
                }
            } else if ("Boolean".equals(item.getDataType())) {
                // 排除项取值区间
                retStr += "==" + (item.getControlValue().equals("1") ? "true" : "false");
            } else {
                String lowerOpt = item.getLowerOpt();
                String upperOpt = item.getUpperOpt();

                if (controlValue.indexOf(",") < 0) return "";
                String[] valArr = controlValue.split(",");
                if (dataType.equals("Date")) {
                    for (int i = 0; i < valArr.length; i++) {
                        valArr[i] = "\"" + valArr[i] + "\"";
                    }
                }
                String expression = retStr;
                if (!StringUtils.isEmpty(lowerOpt) && valArr[0].length() > 0) {
                    if (lowerOpt.equals("[")) {
                        retStr = expression + ">=" + valArr[0];
                    } else {
                        retStr = expression + ">" + valArr[0];
                    }
                } else {
                    retStr = "";
                }
                if (valArr.length == 2) {
                    if (!StringUtils.isEmpty(retStr))
                        retStr += " && ";
                    if (upperOpt.equals("]")) {
                        retStr += expression + "<=" + valArr[1];
                    } else {
                        retStr += expression + "<" + valArr[1];
                    }
                }

//				if (controlValue.indexOf(",") < 0) {
//					return "";
//				}
//				String[] valueArr = controlValue.split(",");
//				String tempExp = expression;
//				
//				if (!StringUtils.isEmpty(item.getLowerOpt())) {
//					// 排除项取值区间
//					if ("[".equals(item.getLowerOpt())) {
//						expression = tempExp + " >= " + valueArr[0];
//					} else {
//						expression = tempExp + " > " + valueArr[0];
//					}
//				}
//				
//				if(valueArr.length == 2) {
//					expression += " && ";
//					// 排除项取值区间
//					if ("]".equals(item.getUpperOpt())) {
//						expression += tempExp + " <= " + valueArr[1];
//					}else{
//						expression += tempExp + " < " + valueArr[1];
//					}
//				}
            }
        } else if ("then".equals(type)) {
            retStr = "ruleHelper.setValue";
            if (!StringUtils.isEmpty(item.getPosition())) {
                retStr = "ruleHelper.insertValue";
            }
            retStr += "($insertMap,\"" + item.getClassName() + "." + item.getNameen() + "\",\"" + item.getControlValue() + "\");\n";
        }

        return retStr;
    }

    /**
     * 生成 RuleItem
     */
    private RuleItem generateRuleItem(String ruleName, int salience, String factExp, String actionExp) {
        RuleItem ruleItem = new RuleItem();
        ruleItem.setRuleName(ruleName);
        ruleItem.setSalience(salience);

        DWhen dWhen = new DWhen();
        Fact fact = new Fact();
        fact.setContent(factExp);
        dWhen.setFirstFact(fact);

        DThen dThen = new DThen();
        Action action = new Action();
        action.setContent(actionExp);
        dThen.getListAction().add(action);

        ruleItem.setdWhen(dWhen);
        ruleItem.setdThen(dThen);

        return ruleItem;
    }
}
